package dbcontext

import (
	"database/sql"
	"errors"
	"fmt"
	"github.com/fatih/color"
	"github.com/ifnk/micro-blog/internal/pkg/config"
	jinzhu "github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/postgres"
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

// 新的 gorm db 迁移数据库用
type GormDB struct {
	*gorm.DB
}

// 老 金珠 gorm 业务 要用
type JinZhuDB struct {
	*jinzhu.DB
}

func NewGormDB(dsn string) (*GormDB, error) {
	//db, err := gorm.Open("postgres", dsn)

	db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
		Logger:                                   logger.Default.LogMode(logger.Info),
		DisableForeignKeyConstraintWhenMigrating: true, // 迁移时禁用外键约束
	})
	if err != nil {
		return nil, err
	}
	return &GormDB{db}, nil
}
func NewJinZhuDB(dsn string) (*JinZhuDB, error) {
	db, err := jinzhu.Open("postgres", dsn)
	db.LogMode(true) // 旧版本 打印sql 语句

	if err != nil {
		return nil, err
	}
	return &JinZhuDB{db}, nil
}

// 检查pg 数据库 是否存在
func checkPGDBExist(dsn string, driver string, createSql string) (bool, error) {
	db, err := sql.Open(driver, dsn)
	if err != nil {
		return false, err
	}
	defer func() {
		err = db.Close()
		if err != nil {
			fmt.Println(err)
		}
	}()
	if err = db.Ping(); err != nil {
		return false, err
	}
	res, err := db.Exec(createSql)
	color.Blue("res -> %+v", res)
	affected, err := res.RowsAffected()
	color.Blue("affected -> %+v", affected)
	return affected != 0, err
}

func createDatabase(dsn string, driver string, createSql string) error {
	db, err := sql.Open(driver, dsn)
	if err != nil {
		return err
	}
	defer func(db *sql.DB) {
		err = db.Close()
		if err != nil {
			fmt.Println(err)
		}
	}(db)
	if err = db.Ping(); err != nil {
		return err
	}
	_, err = db.Exec(createSql)
	return err
}

// 创建数据库(如果没有的话)
func createDB(dbName string, dsn string) error {
	// 创建数据库
	color.Yellow("dsn -> %+v", dsn)
	createSql := "CREATE DATABASE " + dbName
	findCount := fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname = '%s'", dbName)
	color.Blue("findCount -> %+v", findCount)
	exist, err := checkPGDBExist(dsn, "pgx", findCount)
	if err != nil {
		return errors.New(fmt.Sprintf("获取 %+v 是否存在 失败  err -> %+v", dbName, err))
	}
	if !exist {
		color.Blue(" 数据库 %+v 不存在，我来创建数据酷 ", dbName)
		err = createDatabase(dsn, "pgx", createSql)
		if err != nil {
			return errors.New(fmt.Sprintf("创建 permission  数据库失败  err -> %+v", err))
		}
		color.Blue(" 数据库 %+v 创建成功 ", dbName)
		return nil
	}
	color.Blue(" 数据库 %+v 已存在 ", dbName)
	return nil
}

func NewPermissionDB(conf *config.Config) (*GormDB, *JinZhuDB, error) {
	// 先是 只连 host:port    dbName 不写 ，用于创建 数据 库
	emptyDsn := fmt.Sprintf(
		"host=%s user=%s password=%s  port=%s sslmode=disable TimeZone=Asia/Shanghai",
		conf.Permission.DB.Host,
		conf.Permission.DB.User,
		conf.Permission.DB.Password,
		conf.Permission.DB.Port,
	)
	err := createDB(conf.Permission.DB.Name, emptyDsn)
	if err != nil {
		return nil, nil, err
	}
	// 带dbName  用来后面 迁移
	dsn := fmt.Sprintf("%s dbname=%s", emptyDsn, conf.Permission.DB.Name)
	gormDB, err := NewGormDB(dsn)
	if err != nil {
		return gormDB, nil, err
	}
	jinzhuDB, err := NewJinZhuDB(dsn)
	return gormDB, jinzhuDB, err
}
func NewDictDB(conf *config.Config) (*GormDB, *JinZhuDB, error) {
	// 先是 只连 host:port    dbName 不写 ，用于创建 数据 库
	emptyDsn := fmt.Sprintf(
		"host=%s user=%s password=%s  port=%s sslmode=disable TimeZone=Asia/Shanghai",
		conf.Dict.DB.Host,
		conf.Dict.DB.User,
		conf.Dict.DB.Password,
		conf.Dict.DB.Port,
	)
	err := createDB(conf.Dict.DB.Name, emptyDsn)
	if err != nil {
		return nil, nil, err
	}
	// 带dbName  用来后面 迁移
	dsn := fmt.Sprintf("%s dbname=%s", emptyDsn, conf.Dict.DB.Name)
	gormDB, err := NewGormDB(dsn)
	if err != nil {
		return gormDB, nil, err
	}
	jinzhuDB, err := NewJinZhuDB(dsn)
	return gormDB, jinzhuDB, err
}
func NewAuthDB(conf *config.Config) (*GormDB, error) {
	// pg 连接字符串
	//dsn := "host=localhost user=gorm password=gorm dbname=gorm port=9920 sslmode=disable TimeZone=Asia/Shanghai"
	dsn := fmt.Sprintf(
		"host=%s user=%s password=%s dbname=%s port=%s sslmode=disable TimeZone=Asia/Shanghai",
		conf.Auth.DB.Host,
		conf.Auth.DB.User,
		conf.Auth.DB.Password,
		conf.Auth.DB.Name,
		conf.Auth.DB.Port,
	)
	return NewGormDB(dsn)
}

func NewPostDB(conf *config.Config) (*GormDB, *JinZhuDB, error) {
	// 先是 只连 host:port    dbName 不写 ，用于创建 数据 库
	emptyDsn := fmt.Sprintf(
		"host=%s user=%s password=%s  port=%s sslmode=disable TimeZone=Asia/Shanghai",
		conf.Post.DB.Host,
		conf.Post.DB.User,
		conf.Post.DB.Password,
		conf.Post.DB.Port,
	)

	color.Blue("emptyDsn -> %+v", emptyDsn)
	err := createDB(conf.Post.DB.Name, emptyDsn)
	if err != nil {
		return nil, nil, err
	}
	// 带dbName  用来后面 迁移
	dsn := fmt.Sprintf("%s dbname=%s", emptyDsn, conf.Post.DB.Name)
	gormDB, err := NewGormDB(dsn)
	if err != nil {
		return gormDB, nil, err
	}
	jinzhuDB, err := NewJinZhuDB(dsn)
	return gormDB, jinzhuDB, err
}

//com.mikejhill.intellij.movetab.actions.MoveTabRight
func NewCommentDB(conf *config.Config) (*GormDB, *JinZhuDB, error) {
	emptyDsn := fmt.Sprintf(
		"host=%s user=%s password=%s  port=%s sslmode=disable TimeZone=Asia/Shanghai",
		conf.Comment.DB.Host,
		conf.Comment.DB.User,
		conf.Comment.DB.Password,
		conf.Comment.DB.Port,
	)
	color.Blue("emptyDsn -> %+v", emptyDsn)
	err := createDB(conf.Comment.DB.Name, emptyDsn)
	if err != nil {
		color.Blue("createDb 方法失败 err.Error() -> %+v", err.Error())
		return nil, nil, err
	}
	// 带dbName  用来后面 迁移
	dsn := fmt.Sprintf("%s dbname=%s", emptyDsn, conf.Comment.DB.Name)
	gormDB, err := NewGormDB(dsn)
	if err != nil {
		color.Blue("NewGormDB 方法失败 err.Error() -> %+v", err.Error())
		return gormDB, nil, err
	}
	jinzhuDB, err := NewJinZhuDB(dsn)
	return gormDB, jinzhuDB, err
}
